<?php
/**
 * <pre>
 * <b>RUBIK IT Solution & Development ltd.</b>
 *
 * PROJECT      : rubik-base
 * COPYRIGHT    : 2008
 * ------------------------------------------------------
 * 
 * [GENERAL INFO OF THIS FILE] 
 *
 * </pre>
 * 
 * @version 		1.5
 * @author			Dang Nhon Hoa <HoaDN@rubik.com.vn>
 * @access			public
 * @package			rubik.base.dbo
 *
 * Created on	: May 5, 2008
 */
RCoreImporter::cls("dbo.RubikDBField" );
RCoreImporter::cls("dbo.RubikDBFieldList" );
RCoreImporter::cls("dbo.RubikDBInfo" );

RCoreImporter::cls("dbo.RubikDBFactory" );

RCoreImporter::cls("helper.RubikHelper" );

/**
 * The abstract class of RUBIK for management the Database Object
 * <pre>
 * Lớp dùng để tạo ra các câu truy vấn.
 * Các thuộc tính public trong lớp này sẽ tương ứng với các field 
 * 	được lấy ra trong 1 câu query. Và có giá trị mặc định ban đầu theo định dạng sau:
 * 		<b>{data type}[‘*’]|[{default value}]|[{alias}]|[‘key’]</b>
 * 
 * <b><i>Các kiểu dữ liệu và text tương ứng:</i></b>
 * 
 * <b>STT	text	Kiểu dữ liệu	Ghi chú</b>
 * 1	S	String	Nếu các kiểu dữ liệu ko được liêt kê hoặc ko có trong danh sách này thì mặc định là kiểu string.
 * 2	N	Number	Số nguyen
 * 3	F	Float	Số thập phân
 * 4	D	Date	Kiểu dữ liệu ngày
 * 5	DT	DateTime	Kiểu dữ liệu ngày giờ
 * 6	T	Time	Kiểu dữ liệu giờ
 * 7	TS	Time Stamp
 * 8	B	Boolean	Kiểu bít (0/1)
 * 
 * </pre>
 */
class AbstractRubikDBObject extends Object {
	
	/**
	 * Check if this DB object has been prepared data for SQL
	 *
	 * @var boolean
	 */
	var $_isPreparedData = null;
	
	/**
	 * The where clause
	 *
	 * @var string
	 */
	var $_where = null;
	
	/**
	 * Order by clause
	 *
	 * @var string
	 */
	var $_order_by = null;
	
	/**
	 * Constructor
	 *
	 * @param string $from this can be a from clause of just table name.
	 * @param string $where the where clause of this dbo
	 * @param string $orderBy the ORDER BY clause
	 * @param Database $db database object of this DB Info.
	 */
	function __construct($from = '', $where = '', $orderBy = '', $db = null) {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		if ($dbInfo == null) {
			$dbInfo = new RubikDBInfo ( $this, $from, $db );
			RubikDBFactory::setDBInfo ( $this, $dbInfo );
		}
		$dbInfo->_createInfo ( $this );
		$this->resetDefaultValue ();
		$this->setWhereClause ( $where );
		$this->_order_by = $orderBy;
	}
	
	/**
	 * Get the ORDER BY clause of this
	 *
	 * @return string
	 */
	function getOrderBy() {
		return $this->_order_by;
	}
	
	/**
	 * Reset all value into default value
	 */
	function resetDefaultValue() {
		RubikDBFactory::setDefaultValue ( $this );
	}
	
	/**
	 * Set all values into null.
	 *
	 */
	function setAllNullValues() {
		RubikDBFactory::setAllNullValues ( $this );
	}
	
	/**
	 * Set all empty string into null value
	 *
	 */
	function setEmptyToNull() {
		RubikDBFactory::setEmptyToNull ( $this );
	}
	
	/**
	 * Check if this DB object has been prepared data for SQL
	 *
	 * @return boolean
	 */
	function isPreparedData() {
		return $this->_isPreparedData;
	}
	
	/**
	 * Check if this DB object has been prepared data for view?
	 *
	 * @return boolean
	 */
	function isPreparedViewData() {
		return ! $this->_isPreparedData;
	}
	
	/**
	 * Set data for prepared data or not?
	 *
	 * @param boolean $value
	 */
	function setPreparedData($value = true) {
		$this->_isPreparedData = $value;
	}
	
	/**
	 * Binds don't care about sensitive of each name a named array/hash to this object
	 *
	 * Can be overloaded/supplemented by the child class
	 *
	 * @access	public
	 * @param	$from	mixed	An associative array or object
	 * @param	$ignore	mixed	An array or space separated list of fields not to bind
	 * @return	boolean
	 */
	function bindCaseInsensitve($from, $ignore = array()) {
		return RubikHelper::bindCaseInsensitve ( $from, $this, $ignore );
	}
	
	/**
	 * Get from clause
	 *
	 * @return string
	 */
	function setFromClause($fromClause) {
		$dbInfo = &RubikDBFactory::getDBInfo ( $this );
		return $dbInfo->setFromClause ( $fromClause );
	}
	
	/**
	 * Binds don't care about sensitive of each name a named array/hash to this object
	 *
	 * Can be overloaded/supplemented by the child class
	 *
	 * @access	public
	 * @param	$from	mixed	An associative array or object
	 * @param	$ignore	mixed	An array or space separated list of fields not to bind
	 * @return	boolean
	 */
	function bind($from, $ignore = array(), $prefix = "", $ignoreEmpty = false) {
		return RubikHelper::bindCaseSensitve ( $from, $this, $ignore, $prefix, $ignoreEmpty);
	}
	
	/**
	 * Reset all public properties value into null
	 *
	 */
	function resetToNull() {
		RubikHelper::setAllPropertiesToNull ( $this );
	}
	
	/**
	 * Set all empty number fields to Zero number
	 * Using this in case of update some value that data is null
	 *
	 */
	function setEmptyNumberToZero() {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$dbInfo->setEmptyNumberToZero($this);
	}
	
	/**
	 * Set all empty boolean fields to Zero number
	 * Using this in case of update some value that data is null
	 *
	 */
	function setEmptyBooleanToZero() {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$dbInfo->setEmptyBooleanToZero($this);
	}
	
	/**
	 * Get the SELECT count(*) of this DBO
	 *
	 * @return string ex: SELECT count(*) FROM user u JOIN user_group g ON u.group_id = g.group_id
	 */
	function getSelectCountSQL() {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$sql = "SELECT count(1) ";
		$sql .= "\n FROM ( SELECT 1"; // Fix the problem when the SELECT have group by
		$sql .= "\n			" . $dbInfo->getFromClause ();
		$sql .= "\n			" . $this->getWhereClause ();
		$sql .= "\n			" . $this->getOrderBy ();
		$sql .= "\n		) _count";
		return $sql;
	}
	
	/**
	 * Get where clause in DBInfo Object
	 *
	 * @return string
	 */
	function getWhereClause() {
		return $this->_where;
	}
	
	/**
	 * Get the select clause of current DB Object
	 *
	 * @param boolean $includeWhere
	 * @param string $extWhere
	 * @param string $extKey the extend key like: "DISTINCT", "TOP 1", ....
	 * @return string "SELECT user_id, user_name, password FROM user WHERE user_id='1' ORDER BY user_name"
	 */
	function getSelectSQL($includeWhere = true, $extWhere = '', $extKey = '') {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$selectClause = $dbInfo->getSelectSQL ( $extKey );
		
		$hasWhere = false;
		if ($includeWhere && ! empty ( $this->_where )) {
			$selectClause .= "\n" . $this->_where;
			$hasWhere = true;
		}
		if ($includeWhere && ! empty ( $extWhere )) {
			if ($hasWhere) {
				$selectClause .= " AND ($extWhere)";
			} else {
				$selectClause .= "\n WHERE $extWhere";
			}
		}
		if (! empty ( $this->_order_by )) {
			$selectClause .= "\n" . $this->_order_by;
		}
		
		return $selectClause;
	}
	
	/**
	 * Preparing data before insert or doing some calculate
	 * This function could be override by the sub class
	 *
	 * @return boolean
	 */
	function prepareData() {
		if ($this->isPreparedData ()) {
			return false;
		}
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$dbInfo->prepareData ( $this );
		$this->setPreparedData ();
		return true;
	}
	
	/**
	 * Preparing data before using DBO for viewing or doing some calculate
	 * This function could be override by the sub class
	 *
	 * @return boolean
	 */
	function prepareViewData() {
		if ($this->isPreparedViewData ()) {
			return false;
		}
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$dbInfo->prepareViewData ( $this );
		
		$this->setPreparedData ( false );
		return true;
	}
	
	/**
	 * Set value for where clause
	 *
	 * @param string $where
	 */
	function setWhereClause($where) {
		if (empty ( $where )) {
			return;
		}
		$upperWhere = strtoupper ( $where );
		if (strpos ( $upperWhere, "WHERE" ) === false) {
			$this->_where = " WHERE " . $where;
		} else {
			$this->_where = $where;
		}
	}
	
	/**
	 * Remove the slash when php enable mode: magic_quotes_gpc .
	 * Using this function before set data into view.
	 * 
	 * The idea of this: When a form submit then bind value into a DBO (magic_quotes_gpc = on)
	 * if you want to fill data back from current DBO into form --> you must use this function 
	 * for smart strip the slash.
	 * 
	 * Why smart?
	 * 	This function just strip the slash if (magic_quotes_gpc == on)
	 *
	 * @return boolean strip or not?
	 */
	function smartStripSlash() {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$dbInfo->smartStripSlash ( $this );
	}

	/**
	 * If the string is build from the server and don't know should add slashes or not.
	 * Then call this function for smart add slashes or irgonre;
	 * 
	 * 
	 * @return unknown_type
	 */
	function smartAddSlashes() {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$dbInfo->smartAddSlashes( $this );
	}
	/**
	 * Get the database object of current DTO.
	 *
	 * @return Database
	 */
	function &getDatabase() {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		return $dbInfo->getDatabase();
	}
}
?>
